package com.nbcio.online.service.impl;

import java.nio.charset.StandardCharsets;
import java.util.Map;

import com.nbcio.common.core.exception.ServiceException;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

import com.alibaba.fastjson.JSONObject;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.nbcio.common.core.utils.StringUtils;
import com.nbcio.common.mybatis.core.page.PageQuery;
import com.nbcio.common.mybatis.core.page.TableDataInfo;
import com.nbcio.common.satoken.utils.LoginHelper;
import com.nbcio.common.tenant.helper.TenantHelper;
import com.nbcio.generator.domain.GenTable;
import com.nbcio.generator.domain.GenTableColumn;
import com.nbcio.generator.mapper.GenTableMapper;
import com.nbcio.generator.service.IGenTableService;
import com.nbcio.online.domain.vo.DictVo;
import com.nbcio.online.domain.vo.OnlFieldVo;
import com.nbcio.online.domain.vo.TableVo;
import com.nbcio.online.mapper.OnlineMapper;
import com.nbcio.online.service.IFormService;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;


/**
 * online表单 服务层实现
 *
 * @author nbacheng
 */

@Slf4j
@RequiredArgsConstructor
@Service
public class FormServiceImpl implements IFormService {

	private final GenTableMapper baseMapper;
	private final IGenTableService genTableService;
	private final OnlineMapper onlineMapper;

	@Override
	public Map<String, Object> getOnlineForm(Long tableId) {
        GenTable table = genTableService.selectGenTableById(tableId);
        TableVo tableVo = new TableVo();
        BeanUtils.copyProperties(table, tableVo);
        tableVo.setColumnsVo(processColumns(table.getColumns()));

        Map<String, Object> result = new HashMap<>();
        if ("main".equals(table.getTplCategory())) {
            GenTable subTable = baseMapper.selectGenTableByName(table.getSubTableName());
            TableVo subVo = new TableVo();
            BeanUtils.copyProperties(subTable, subVo);
            subVo.setColumnsVo(processColumns(subTable.getColumns()));
            //过滤子表ID列（新增过滤逻辑）
            List<OnlFieldVo> filteredColumns = processColumns(subTable.getColumns()).stream()
                .filter(column ->
                    !"id".equals(column.getColumnName()) &&  // 过滤 id
                        !table.getSubTableFkName().equals(column.getColumnName())  // 过滤外键（main_id）
                )
                .collect(Collectors.toList());
            subVo.setColumnsVo(filteredColumns);

            result.put("type", "main-sub");
            result.put("main", tableVo);
            result.put("sub", subVo);
            result.put("foreignKey", table.getSubTableFkName());
        } else if ("single".equals(table.getTplCategory())) {
            result.put("type", "single");
            result.put("data", tableVo);
        } else if ("sub".equals(table.getTplCategory())) {
            result.put("type", "sub");
            result.put("data", tableVo);
        }
        return result;
	}

    // 处理字段公共方法
    private List<OnlFieldVo> processColumns(List<GenTableColumn> columns) {
        return columns.stream()
            .filter(col -> !isSystemField(col.getColumnName()))
            .map(col -> {
                OnlFieldVo vo = new OnlFieldVo();
                BeanUtils.copyProperties(col, vo);
                if (StringUtils.isNotEmpty(col.getDictType())) {
                    vo.setCommonDictCode(getColumnDict(col));
                }
                return vo;
            }).collect(Collectors.toList());
    }

    private boolean isSystemField(String columnName) {
        return StringUtils.equalsAnyIgnoreCase(columnName,
            "create_by", "create_time", "create_dept", "update_by", "update_time", "tenant_id");
    }

    // 修改保存方法
    @Transactional
    public void saveMainSubData(Long mainTableId, Map<String, Object> mainData, List<Map<String, Object>> subDataList) {
        // 保存主表
        GenTable mainTable = genTableService.selectGenTableById(mainTableId);
        String pkName = getPkName(mainTableId);
        int mainResult = addOrUpdateOnlineData(mainTableId, mainTable.getTableName(), mainData);

        if (mainResult > 0 && !CollectionUtils.isEmpty(subDataList)) {
            Object mainId = mainData.get(pkName);
            // 删除旧子表数据
            deleteSubByForeignKey(mainTable, mainId);

            // 保存新子表数据
            subDataList.forEach(sub -> {
                sub.put(mainTable.getSubTableFkName(), mainId);
                addOrUpdateOnlineData(
                    baseMapper.selectGenTableByName(mainTable.getSubTableName()).getTableId(),
                    mainTable.getSubTableName(),
                    sub
                );
            });
        }
    }

    private void deleteSubByForeignKey(GenTable mainTable, Object mainId) {
        onlineMapper.deleteSubByForeignKey(
            mainTable.getSubTableName(),
            mainTable.getSubTableFkName(),
            mainId
        );
    }

	@Override
	public TableDataInfo<GenTable> selectPageGenTableList(GenTable genTable, PageQuery pageQuery) {
		Page<GenTable> page = baseMapper.selectPage(pageQuery.build(), this.buildGenTableQueryWrapper(genTable));
        return TableDataInfo.build(page);
	}

	private QueryWrapper<GenTable> buildGenTableQueryWrapper(GenTable genTable) {
        Map<String, Object> params = genTable.getParams();
        QueryWrapper<GenTable> wrapper = Wrappers.query();
        wrapper
            .eq(StringUtils.isNotEmpty(genTable.getDataName()),"data_name", genTable.getDataName())
            .like(StringUtils.isNotBlank(genTable.getTableName()), "lower(table_name)", StringUtils.lowerCase(genTable.getTableName()))
            .like(StringUtils.isNotBlank(genTable.getTableComment()), "lower(table_comment)", StringUtils.lowerCase(genTable.getTableComment()))
            .between(params.get("beginTime") != null && params.get("endTime") != null,
                "create_time", params.get("beginTime"), params.get("endTime"));
        return wrapper;
    }

    public  List<DictVo> getColumnDict(GenTableColumn onlColumn){
    	String dictType = onlColumn.getDictType();
    	if (StringUtils.isNotEmpty(dictType)) {
    		List<DictVo> dictVoList = onlineMapper.getDictData(dictType, TenantHelper.getTenantId());
    		return dictVoList;
    	}
		return null;
    }

	@Override
	public TableDataInfo<Map> listOnlineData(Long tableId, String tableName, PageQuery pageQuery) {
		QueryWrapper<Map> wrapper = Wrappers.query();
		wrapper.eq("tenant_id", TenantHelper.getTenantId());
		JSONObject params = pageQuery.getParams();
		if (ObjectUtils.isNotEmpty(params)) {
			//遍历查询JSON对象
			for(String key : params.keySet()) {
				Object queryValue = params.get(key);
				wrapper.eq(key,queryValue);
			}
		}
		Page<Map> page = onlineMapper.getOnlineData(tableName, pageQuery.build(), wrapper);
		List<Map> records = page.getRecords();
		Map<String, Object> onlineField = getOnlineForm(tableId);
        TableVo tableVo = new TableVo();
        if ( onlineField.get("type").equals("single") ) {
            tableVo = (TableVo) onlineField.get("data");
        }
        else if( onlineField.get("type").equals("main-sub") ) {
            tableVo = (TableVo) onlineField.get("main");
        }
        else if( onlineField.get("type").equals("sub") ) {
            tableVo = (TableVo) onlineField.get("data");
        }
		List<OnlFieldVo> columnsList = tableVo.getColumnsVo();
		for (Map map : records) { //对longblob数据类型做特殊处理
			for (OnlFieldVo onlineFieldVo : columnsList) {
				if ( StringUtils.equalsAny(onlineFieldVo.getColumnType(), "longblob")) {
					Object blob = (Object) map.get(onlineFieldVo.getColumnName());
					String content;
                    if(ObjectUtils.isNotEmpty(blob)) {
                        content = new String((byte[])blob, StandardCharsets.UTF_8);
                    }
                    else {
                        content = "";
                    }
                    map.put(onlineFieldVo.getColumnName(), content); // 更新longblob内容
                }
			}
		}
		page.setRecords(records);
		return TableDataInfo.build(page,onlineField);
	}

    @Override
    @Transactional
    public int addOrUpdateOnlineData(Long tableId, String tableName, Map<String, Object> map) {
        // 判断是否为主子表结构
        boolean isMainSub = map.containsKey("main") && map.containsKey("sub");

        // 处理主表数据
        Map<String, Object> mainData = isMainSub ? (Map<String, Object>) map.get("main") : map;
        // 获取表结构信息
        GenTable table = genTableService.selectGenTableById(tableId);

        String mainPkName = getPkName(tableId);

        int result = 0;

        try {
            if (isMainSub) {
                // ============= 主子表处理逻辑 =============
                Map<String, Object> subData = (Map<String, Object>) map.get("sub");
                String subTableName = (String) subData.get("tableName");
                List<Map<String, Object>> subRows = (List<Map<String, Object>>) subData.get("data");

                // 处理主表
                Object mainId = processMainTable(tableName, mainData, mainPkName);
                String fkName = getSubTableFk(table); // 这里table是主表的GenTable对象

                // 处理子表
                if (mainId != null && subRows != null && !subRows.isEmpty()) {
                    processSubTable(subTableName, fkName, mainId, subRows);
                }

                result = 1;
            } else {
                // ============= 单表处理逻辑 =============
                result = processSingleTable(tableName, mainData, mainPkName);
            }

        } catch (Exception e) {
            throw new ServiceException("操作失败：" + e.getMessage());
        }
        return result;
    }

    private Object processMainTable(String tableName, Map<String, Object> data, String pkName) {
        boolean isUpdate = data.containsKey(pkName) && ObjectUtils.isNotEmpty(data.get(pkName));
        Object mainId = null;

        if (isUpdate) {
            // 更新主表
            handleCommonFields(data, false);
            Map<String, Object> where = new HashMap<>();
            where.put(pkName, data.get(pkName));
            data.remove(pkName);
            onlineMapper.dynamicUpdate(tableName, data, where);
            mainId = where.get(pkName);
        } else {
            // 新增主表
            handleCommonFields(data, true);
            onlineMapper.insertDynamic(tableName, data);
            // 获取自增主键（根据具体数据库实现）
            mainId = data.get(pkName);
        }
        return mainId;
    }

    private void processSubTable(String subTableName, String fkName, Object mainId,
                                 List<Map<String, Object>> subRows) {
        // 删除旧子表数据（更新时）
        if (mainId != null) {
            Map<String, Object> deleteWhere = new HashMap<>();
            deleteWhere.put(fkName, mainId);
            onlineMapper.dynamicDelete(subTableName, deleteWhere);
        }

        // 插入新子表数据
        for (Map<String, Object> row : subRows) {
            row.put(fkName, mainId); // 关联主表ID
            handleCommonFields(row, true);
            onlineMapper.insertDynamic(subTableName, row);
        }
    }

    private int processSingleTable(String tableName, Map<String, Object> data, String pkName) {
        if (data.containsKey(pkName) && ObjectUtils.isNotEmpty(data.get(pkName))) {
            // 更新操作
            handleCommonFields(data, false);
            Map<String, Object> where = new HashMap<>();
            where.put(pkName, data.get(pkName));
            data.remove(pkName);
            return onlineMapper.dynamicUpdate(tableName, data, where);
        } else {
            // 新增操作
            handleCommonFields(data, true);
            return onlineMapper.insertDynamic(tableName, data);
        }
    }

    private void handleCommonFields(Map<String, Object> data, boolean isCreate) {
        // 公共字段处理
        Long userId = LoginHelper.getUserId();
        Long deptId = LoginHelper.getDeptId();
        String time = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));

        if (isCreate) {
            data.put("tenant_id", TenantHelper.getTenantId());
            data.put("create_by", userId);
            data.put("create_dept", deptId);
            data.put("create_time", time);
        } else {
            data.put("update_by", userId);
            data.put("update_time", time);
        }

        // 移除可能存在的空字段
        data.entrySet().removeIf(entry -> entry.getValue() == null);
    }

    @Override
    @Transactional
    public void deleteOnlineData(Long tableId, String tableName, List<Long> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            throw new IllegalArgumentException("删除ID不能为空");
        }

        // 获取主表元数据
        GenTable table = genTableService.selectGenTableById(tableId);
        String pkName = getPkName(tableId);

        // 处理子表数据删除（如果存在）
        if (isHasSubTable(table)) {  // 新增判断是否存在子表的方法
            String fkName = getSubTableFk(table);
            String subName = table.getSubTableName();

            Map<String, Object> deleteWhere = new HashMap<>();
            deleteWhere.put(fkName, ids);
            onlineMapper.dynamicDelete(subName, deleteWhere);
        }

        // 删除主表数据
        onlineMapper.deleteDynamicTable(tableName, pkName, ids);
    }

    // 判断是否存在子表
    private boolean isHasSubTable(GenTable table) {
        return table != null
            && StringUtils.isNotBlank(table.getSubTableName())
            && StringUtils.isNotBlank(getSubTableFk(table));
    }

	@Override
    public Map<String, Object> getOnlineData(Long tableId, String tableName, Long id) {
        // 参数校验
        if (id == null) {
            throw new IllegalArgumentException("ID不能为空");
        }

        // 获取表结构信息
        GenTable table = genTableService.selectGenTableById(tableId);
        List<GenTableColumn> columnsList = table.getColumns();

        // 提取主键列名
        String pkName = columnsList.stream()
            .filter(column -> "1".equals(column.getIsPk()))
            .findFirst()
            .map(GenTableColumn::getColumnName)
            .orElseThrow(() -> new RuntimeException("表" + tableName + "无主键"));

        // 获取表的字段配置信息
        Map<String, Object> onlineField = getOnlineForm(tableId);
        String formType = (String) onlineField.get("type");

        // 构建返回结果
        Map<String, Object> result = new HashMap<>();

        // 处理单表模式
        if ("single".equals(formType)) {
            TableVo tableVo = (TableVo) onlineField.get("data");
            Map<String, Object> data = onlineMapper.selectDynamicTableById(tableName, pkName, id);
            processBlobFields(tableVo.getColumnsVo(), data);
            result.putAll(data);
        }
        // 处理主子表模式
        else if ("main-sub".equals(formType)) {
            // 获取主表配置
            TableVo mainTable = (TableVo) onlineField.get("main");
            // 获取子表配置
            TableVo subTable = (TableVo) onlineField.get("sub");

            // 查询主表数据
            Map<String, Object> mainData = onlineMapper.selectDynamicTableById(tableName, pkName, id);
            processBlobFields(mainTable.getColumnsVo(), mainData);
            removeSystemFields(mainData);  // 新增过滤逻辑
            result.put("main", mainData);

            // 查询子表数据（假设子表通过外键关联）
            String subTableName = subTable.getTableName();
            // 需要传入主表对象
            String fkName = getSubTableFk(table); // 这里table是主表的GenTable对象

            List<Map<String, Object>> subData = onlineMapper.selectSubTableByFk(
                subTableName,
                fkName,
                (Long) mainData.get(pkName)
            );
            processBlobFields(subTable.getColumnsVo(), subData);
            subData.forEach(this::removeSystemFields);  // 新增过滤逻辑
            result.put(subTableName, subData);
        }

        return result;
    }

    private void removeSystemFields(Map<String, Object> data) {
        List<String> keysToRemove = new ArrayList<>();
        for (String key : data.keySet()) {
            if (isSystemField(key)) {
                keysToRemove.add(key);
            }
        }
        keysToRemove.forEach(data::remove);
    }

    // 处理longblob字段的通用方法
    private void processBlobFields(List<OnlFieldVo> columns, Map<String, Object> data) {
        for (OnlFieldVo field : columns) {
            if ("longblob".equals(field.getColumnType())) {
                Object value = data.get(field.getColumnName());
                if (value instanceof byte[]) {
                    data.put(field.getColumnName(), new String((byte[]) value, StandardCharsets.UTF_8));
                }
            }
        }
    }

    // 处理子表列表的blob字段
    private void processBlobFields(List<OnlFieldVo> columns, List<Map<String, Object>> dataList) {
        for (Map<String, Object> data : dataList) {
            processBlobFields(columns, data);
        }
    }

    private String getPkName(Long tableId) {
        GenTable table = genTableService.selectGenTableById(tableId);
        List<GenTableColumn> columnsList = table.getColumns();
        String pkName="";
        //获取pk
        for (GenTableColumn genTableColumn : columnsList) {
            String isPk = (String) genTableColumn.getIsPk();
            if (StringUtils.equals(isPk, "1")) {
                pkName = genTableColumn.getColumnName();
            }
        }
        return pkName;
    }

    private String getSubTableFk(GenTable mainTable) {
        // 从主表配置中直接获取子表外键字段名
        String fkName = mainTable.getSubTableFkName();

        if (StringUtils.isBlank(fkName)) {
            throw new RuntimeException("子表外键未配置，请检查表["
                + mainTable.getTableName()
                + "]的sub_table_fk_name字段配置");
        }

        return fkName;
    }

    // 动态表分页查询
    @Override
    public TableDataInfo selectDynamicTablePage(String tableName, QueryWrapper<?> wrapper, Page<?> page) {
        // 校验表名合法性（防止SQL注入）
        if (!isValidTableName(tableName)) {
            throw new ServiceException("非法表名");
        }

        // 使用MyBatis Plus的分页查询
        Page<Map<String, Object>> resultPage = onlineMapper.selectDynamicPage(
            page,
            tableName,
            wrapper
        );

        return TableDataInfo.build(resultPage);
    }

    // 动态表单条查询
    @Override
    public Map<String, Object> selectDynamicTableById(String tableName, String id) {
        if (!isValidTableName(tableName)) {
            throw new ServiceException("非法表名");
        }

        QueryWrapper<Map<String, Object>> wrapper = new QueryWrapper<>();
        wrapper.eq("id", id); // 假设主键字段为id

        return onlineMapper.selectDynamicOne(tableName, wrapper);
    }

    // 校验表名合法性（字母数字下划线）
    private boolean isValidTableName(String tableName) {
        return tableName.matches("^[a-zA-Z0-9_]+$");
    }

	@Override
	public TableDataInfo<Map> listTableData(String tableName, PageQuery pageQuery) {
		QueryWrapper<Map> wrapper = Wrappers.query();
		wrapper.eq("tenant_id", TenantHelper.getTenantId());
		JSONObject params = pageQuery.getParams();
		if (ObjectUtils.isNotEmpty(params)) {
			//遍历查询JSON对象
			for(String key : params.keySet()) {
				Object queryValue = params.get(key);
				wrapper.eq(key,queryValue);
			}
		}
		Page<Map> page = onlineMapper.getOnlineData(tableName, pageQuery.build(), wrapper);
		//List<Map> records = page.getRecords();
		return TableDataInfo.build(page);
	}

    @Override
    public int addOrUpdateOnlineDataByName(String tableName, Map<String, Object> map) {
        // 判断是否为主子表结构
        boolean isMainSub = map.containsKey("main") && map.containsKey("sub");

        // 处理主表数据
        Map<String, Object> mainData = isMainSub ? (Map<String, Object>) map.get("main") : map;
        // 获取表结构信息
        GenTable table = baseMapper.selectGenTableByName(tableName);

        String mainPkName = getPkName(table.getTableId());

        int result = 0;

        try {
            if (isMainSub) {
                // ============= 主子表处理逻辑 =============
                Map<String, Object> subData = (Map<String, Object>) map.get("sub");
                String subTableName = (String) subData.get("tableName");
                List<Map<String, Object>> subRows = (List<Map<String, Object>>) subData.get("data");

                // 处理主表
                Object mainId = processMainTable(tableName, mainData, mainPkName);
                String fkName = getSubTableFk(table); // 这里table是主表的GenTable对象

                // 处理子表
                if (mainId != null && subRows != null && !subRows.isEmpty()) {
                    processSubTable(subTableName, fkName, mainId, subRows);
                }

                result = 1;
            } else {
                // ============= 单表处理逻辑 =============
                result = processSingleTable(tableName, mainData, mainPkName);
            }

        } catch (Exception e) {
            throw new ServiceException("操作失败：" + e.getMessage());
        }
        return result;
    }
}
